import shutil
from urllib.parse import urlparse, parse_qs
import os
import requests
import mimetypes

from src import logger
from src.utils.logger import get_logger
from typing import List, Any
import config
from src.utils.oss import upload_to_oss

logger = get_logger("capcut")

def get_url_param(url: str, key: str, default=None):
    """
    从 URL 中提取指定查询参数的值（返回第一个值）。
    若参数不存在，返回 default。
    """
    query = parse_qs(urlparse(url).query)
    return query.get(key, [default])[0]

def print_app_routes(routes: List[Any]):
    """
    打印所有路由地址
    """
    for r in routes:
        # 1. 取 HTTP 方法列表
        methods = getattr(r, "methods", None) or [getattr(r, "method", "WS")]
        # 2. 取路径
        path = r.path
        # 3. 取函数名
        name = r.name
        logger.info("Route: %s %s -> %s", ",".join(sorted(methods)), path, name)

def download(url, save_dir, filename, limit=30*1024*1024, timeout=300) -> str:
    """
    下载文件并根据Content-Type判断文件类型
    
    Args:
        url: 文件的URL地址
        save_dir: 文件保存目录
        filename: 文件名
        limit: 文件大小限制（字节），默认30MB
        timeout: 整体下载超时时间（秒），默认5分钟
    
    Returns:
        完整的文件路径
        
    Raises:
        Exception: 下载过程中出现任何错误
    """
    save_path = os.path.join(save_dir, filename)
    
    try:
        # 发送GET请求下载文件
        response = requests.get(url, stream=True, timeout=timeout)
        response.raise_for_status()
        
        # 获取Content-Type
        content_type = response.headers.get('Content-Type', '').split(';')[0].strip()
        
        # 如果没有扩展名，则根据Content-Type猜测扩展名
        if '.' not in filename:
            extension = mimetypes.guess_extension(content_type)
            if extension:
                filename += extension
                # 更新保存路径
                save_path = os.path.join(save_dir, filename)

        # 下载文件并实时检查大小
        downloaded_size = 0
        with open(save_path, 'wb') as f:
            for chunk in response.iter_content(chunk_size=8192):
                if chunk:
                    f.write(chunk)
                    downloaded_size += len(chunk)
                    
                    # 检查文件大小是否超过限制
                    if downloaded_size > limit:
                        # 删除部分下载的文件
                        f.close()
                        os.remove(save_path)
                        raise Exception(f"文件大小超过{limit/1024/1024:.2f}MB限制")
        
        # 验证下载完整性（如果服务器提供了Content-Length）
        content_length = response.headers.get('Content-Length')
        if content_length and os.path.getsize(save_path) != int(content_length):
            os.remove(save_path)
            raise Exception(f"文件下载不完整: 期望{content_length}字节, 实际{os.path.getsize(save_path)}字节")
        
        return save_path

    except requests.exceptions.RequestException as e:
        # 清理可能已部分下载的文件
        if os.path.exists(save_path):
            os.remove(save_path)
        raise Exception(f"下载失败: {str(e)}")
    except IOError as e:
        # 清理可能已部分下载的文件
        if os.path.exists(save_path):
            os.remove(save_path)
        raise Exception(f"文件写入失败: {str(e)}")
    except Exception as e:
        # 清理可能已部分下载的文件
        if os.path.exists(save_path):
            os.remove(save_path)
        raise e

def generate_draft_url(draft_id):
    return f"{config.DRAFT_URL}{config.DRAFT_PREVIEW_URL}?draft_id={draft_id}&is_capcut={1 if config.IS_CAPCUT_ENV else 0}"

def video_upload_to_oss( local_path: str) -> str:
    """上传视频到OSS"""
    try:
        oss_url = upload_to_oss(local_path)
        logger.info(f"视频上传成功: {oss_url}")
        return oss_url

    except Exception as e:
        logger.error(f"OSS上传失败: {str(e)}")
        raise e

def cleanup_temp_file(file_path: str) -> None:
    """清理临时文件"""
    if os.path.exists(file_path):
        try:
            os.remove(file_path)
            logger.info(f"临时文件已清理: {file_path}")
        except Exception as e:
            logger.error(f"临时文件清理失败: {str(e)}")

def cleanup_temp_draft_file(draft_id: str) -> None:
    """清理临时文件"""
    if os.path.exists(os.path.join(config.DRAFT_DIR, draft_id)):
        try:
            shutil.rmtree(os.path.join(config.DRAFT_DIR, draft_id))
            logger.info(f"草稿文件已清理: {os.path.join(config.DRAFT_DIR, draft_id)}")
        except Exception as e:
            logger.error(f"草稿文件清理失败: {str(e)}")

